package org.axed.user.client.axessory;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import org.axed.user.client.AxedArea;
import org.axed.user.client.AxedListener;
import org.axed.user.client.AxedEvent;
import org.axed.user.client.CaretBase;
import org.axed.user.client.CaretWidget;
import org.axed.user.client.Coords;
import org.axed.user.client.CursesElement;
import org.axed.user.client.DOM;
import org.axed.user.client.HtmlString;
import org.axed.user.client.SpaceString;

/**
 * Displays cursor position info, and size. 
 */
public class VimBar extends CaretWidget implements AxedListener {
	public final static int MESSAGE_NORMAL   = 0;
	public final static int MESSAGE_BOLD     = 1;
	public final static int MESSAGE_RED      = 2;
	public final static int MESSAGE_VERY_RED = 3;

	private CursesElement curse;
	private String message = "";
	private int displayMode = MESSAGE_NORMAL;

	public int caretPos = -1;

	private CaretBase caret;

	private AxedArea axed;

	private int mode = VimInput.MODE_NORMAL;

	/**
	 * Constructor.
	 */
	public VimBar(AxedArea axed, Element outDiv) {
		this.axed = axed;
		if (outDiv == null) {
			outDiv = DOM.createDiv();
		}
		DOM.setStyleAttribute(outDiv, "width", "100%");
		DOM.setStyleAttribute(outDiv, "cursor", "text");
		DOM.setStyleAttribute(outDiv, "fontFamily", "monospace");
		DOM.setStyleAttribute(outDiv, "cursor", "text");
		DOM.setStyleAttribute(outDiv, "overflow", "hidden");
		DOM.setStyleAttribute(outDiv, "position", "relative");
		DOM.setStyleAttribute(outDiv, "zIndex", "1");
		setElement(outDiv);

		scrollDiv = DOM.createDiv();
		//DOM.setStyleAttribute(scrollDiv, "overflow", "auto");
		DOM.setStyleAttribute(scrollDiv, "overflow", "hidden");
		DOM.setStyleAttribute(scrollDiv, "width", "100%");
		DOM.setStyleAttribute(scrollDiv, "position", "relative");
		DOM.setStyleAttribute(scrollDiv, "cursor", "text");
		DOM.setStyleAttribute(scrollDiv, "paddingLeft",  borderLeft + "px");
		DOM.setStyleAttribute(scrollDiv, "paddingRight", borderRight + "px");
		DOM.setStyleAttribute(scrollDiv, "zIndex", "1");
		DOM.appendChild(outDiv, scrollDiv);

		curse = new CursesElement();
		DOM.setStyleAttribute(curse.getElement(), "fontSize", axed.document.fontSize);
		DOM.setStyleAttribute(curse.getElement(), "fontFamily", "monospace");
		DOM.appendChild(scrollDiv, curse.getElement());

		caret = new CaretBase(this, false);
		sinkEvents(Event.ONCLICK);
	}

	/** 
	 * Handles events generated by axed.
	 * Positions the caret when necessary.
	 */
	public void onAxedEvent(AxedEvent event) {
		switch (event.type) {
		case AxedEvent.INSERT_CHAR :
		case AxedEvent.INSERT_TEXT :
		case AxedEvent.JOIN_LINE : 
		case AxedEvent.MOVE_CURSOR : 
		case AxedEvent.REMOVE_CHAR : 
		case AxedEvent.REMOVE_TEXT : 
		case AxedEvent.SPLIT_LINE : 
			update();
			break;
		case AxedEvent.REFRESH :
		case AxedEvent.FONT_SIZE_CHANGED :
		case AxedEvent.SCROLL :
			showMode(mode);
		}
	}

	public void showMode(int mode) {
		this.mode = mode;
		switch (mode) {
		case VimInput.MODE_NORMAL :
			message = "";
			displayMode = MESSAGE_NORMAL;
			break;
		case VimInput.MODE_INSERT :
			message = "-- INSERT --";
			displayMode = MESSAGE_BOLD;
			break;
		case VimInput.MODE_VISUAL :
			message = "-- VISUAL --";
			displayMode = MESSAGE_BOLD;
			break;
		case VimInput.MODE_VISUAL_LINE :
			message = "-- VISUAL LINE --";
			displayMode = MESSAGE_BOLD;
			break;
		default :
			Window.alert("assert=false, mode=" + mode);
			assert false;
		}
		update();
	}

	public void showMessage(String s, int displayMode) {
		message = s;
		this.displayMode = displayMode;
		update();
	}
			

	public void setHighlight(boolean highlight) {
		if (highlight) {
			DOM.setStyleAttribute(curse.getElement(), "background", "#FFFFAD");
		} else {
			DOM.setStyleAttribute(curse.getElement(), "background", "transparent");
		}
	}

	public void cursesMessage(String msg, int curs) {
		message = "";
		caretPos = curs;
		HtmlString text = curse.text;
		text.clear();
		text.appendCol(msg);
		update();
	}

	private void update() {
		HtmlString text = curse.text;
		if (caretPos < 0) {
			caret.hide();
			text.clear();
			switch (displayMode) {
			case MESSAGE_BOLD     : text.appendEntry("<b>"); break;
			case MESSAGE_RED      : text.appendEntry("<span style=\"color: red;\">"); break;
			case MESSAGE_VERY_RED : text.appendEntry("<span style=\"background-color: red; color: white;\">"); break;
			}
			text.appendCol(message);
			switch (displayMode) {
			case MESSAGE_BOLD     : text.appendEntry("</b>"); break;
			case MESSAGE_RED      : text.appendEntry("</span>"); break;
			case MESSAGE_VERY_RED : text.appendEntry("</span>"); break;
			}
			int wc = axed.getWidth() / axed.document.getColWidth();
			int l = wc - message.length() - 10;
			String sx = "";
			for (int i = 0; i < l; i++) {
				sx += "&nbsp;";
			}
			text.appendCol(sx);

			String s = (axed.getCursorLine() + 1) + "," + axed.getCursorCol();
			text.appendCol(s);
			curse.refresh();
		} else {
			curse.refresh();
			caret.position();
			caret.show();
		}
	}

	public void setCaret(int p) {
		caretPos = p;
		update();
	}


	/**
	 * Return the coordinates of the cursor
	 */
	public void getCursorCoords(Coords coords) {
		curse.getCoords(curse.text.entryOf(caretPos), coords);
	}

	/**
	 * TODO
	 */
	public void insertChar(char c) {
		String s;
		if (c != ' ') {
			s = SpaceString.charToHTML(c);
		} else {
			s = "&nbsp;";
		}
		curse.text.insertCol(s, caretPos);
		caretPos++;
		curse.refresh();
		caret.position();
	}

	public boolean backspace() {
		if (caretPos <= 1) {
			return false;
		}

		curse.text.removeCol(caretPos - 1);
		caretPos--;
		curse.refresh();
		caret.position();
		return true;
	}

	public boolean del() {
		if (caretPos >= curse.text.entries()) {
			return false;
		}

		curse.text.removeCol(caretPos);
		curse.refresh();
		caret.position();
		return true;
	}

	public boolean caretPos1() {
		if (caretPos <= 1) {
			return false;
		}

		caretPos = 1;
		curse.refresh();
		caret.position();
		return true;
	}


	public boolean caretLeft() {
		if (caretPos <= 1) {
			return false;
		}

		caretPos--;
		curse.refresh();
		caret.position();
		return true;
	}
	
	public boolean caretEnd() {
		if (caretPos >= curse.text.entries()) {
			return false;
		}

		caretPos = curse.text.entries();
		curse.refresh();
		caret.position();
		return true;
	}

	public boolean caretRight() {
		if (caretPos >= curse.text.entries()) {
			return false;
		}

		caretPos++;
		curse.refresh();
		caret.position();
		return true;
	}

	/**
	 * Handles all browser events
	 */
	public void onBrowserEvent(Event event) {
		switch (DOM.eventGetType(event)) {
		case Event.ONCLICK:
			axed.setFocus(true);
			return;
		}
	}
}
